package com.jvup.common.utils;

import android.annotation.SuppressLint;

import androidx.annotation.NonNull;
import androidx.lifecycle.GenericLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;

import java.util.concurrent.CopyOnWriteArrayList;

import static androidx.lifecycle.Lifecycle.State.DESTROYED;

/**
 * 生命周期计划任务<br/>
 * 在未来某个时刻完成一个计划任务，这个计划可以使一次UI操作，也可以是一次API调用。
 * 可以为这个计划任务添加一个执行条件，如果条件成熟立刻执行，如果了解未达到，将会在条件达到时执行。
 * 这个条件一定是伴随Activity或Fragment生命周期相关的，可以附加一些额外的条件，比如在onCrate构建View完成之后，且某一另外的任务也执行完成后才执行*/
@SuppressLint("RestrictedApi")
public class ScheduledTaskHelper implements GenericLifecycleObserver {

    private final CopyOnWriteArrayList<ScheduledTask> taskList = new CopyOnWriteArrayList();
    private final Lifecycle lifecycle;

    private volatile boolean toTasking = false;
    private volatile int     addTaskCounter = 0;

    public ScheduledTaskHelper(Lifecycle lifecycle) {
        this.lifecycle = lifecycle;
        lifecycle.addObserver(this);
    }

    public void destroy(){
        taskList.clear();
        lifecycle.removeObserver(this);
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (lifecycle.getCurrentState() == DESTROYED) {
            destroy();
            return;
        }
        toTasking = true;
        doTask();
        toTasking = false;
    }

    public void removeTask(ScheduledTask task){
        taskList.remove(task);
    }

    public void addTask(ScheduledTask task){
        taskList.add(task);
    }

    public <T> SimpleTask<T> buildTask(T data){
        return new SimpleTask<T>(this,data);
    }

    /**
     * 同步执行任务，在每次任务添加时，都会同步执行一次任务，为了避免条件已经成熟而未命中任务的情况。
     * */
    public void addAndDoTask(ScheduledTask task){
        addTask(task);
        boolean isReentrance = addTaskCounter != 0 || toTasking;
        addTaskCounter++;
        syncDoTask(task);
        if(!isReentrance) {
            doTask();
        }
        addTaskCounter--;
    }

    private void doTask(){
        for(ScheduledTask task : taskList){
            syncDoTask(task);
        }
    }

    private void syncDoTask(ScheduledTask task){
        if(task.conditional(lifecycle)){
            if(task.doTask(lifecycle)){
                removeTask(task);
            }
        }
    }

    /**
     * 计划任务
     * */
    public interface ScheduledTask {
        /**
         * 任务执行条件，只有当条件达到时才会执行。
         * @param lifecycle 与计划任务绑定的Activity或Fragment的生命周期监听
         * @return 如果返回true则表示执行任务的条件已经达到可以执行计划，false这表示还未达到。
         * */
        boolean conditional(Lifecycle lifecycle);
        /**
         * 任务执行程序，你希望这个任务要做的事。
         * @param lifecycle 与计划任务绑定的Activity或Fragment的生命周期监听
         * @return 如果返回true则表示该任务在达到条件后只会执行一次就从任务列表里移除，如果false则会一直在条件达到时执行。
         * */
        boolean doTask(Lifecycle lifecycle);
    }

    public static final class SimpleTask<T> implements ScheduledTask {

        @NonNull
        private final T data;
        @NonNull
        private Conditional conditional;
        @NonNull
        private Task<T> task;

        @NonNull
        private ScheduledTaskHelper taskHelper;

        private SimpleTask(ScheduledTaskHelper taskHelper, T data) {
            this.data = data;
            this.taskHelper = taskHelper;
        }

        @Override
        public boolean conditional(Lifecycle lifecycle) {
            if(conditional != null)
                return conditional.conditional(lifecycle);
            return true;
        }

        @Override
        public boolean doTask(Lifecycle lifecycle) {
            if(task != null)
                return task.doTask(data);
            return true;
        }

        private boolean isAtLeast(Lifecycle lifecycle,Lifecycle.State targetState) {
            return lifecycle.getCurrentState().isAtLeast(targetState);
        }

        public SimpleTask<T> setConditional(Conditional conditional) {
            this.conditional = conditional;
            return this;
        }

        public SimpleTask<T> setConditional(final Lifecycle.State targetState) {
            this.conditional = (Lifecycle lifecycle) -> isAtLeast(lifecycle,targetState);
            return this;
        }

        public SimpleTask<T> setTask(Task<T> task) {
            this.task = task;
            return this;
        }

        public void submitAndDoTask() {
            taskHelper.addAndDoTask(this);
            taskHelper = null;
        }

        public interface Conditional{
            boolean conditional(Lifecycle lifecycle);
        }

        public interface Task<T>{
            /**
             * 做一个任务
             * @param  data 投递给任务处理的数据
             * @return 如果返回true则表示该任务在达到条件后只会执行一次就从任务列表里移除，如果false则会一直在条件达到时执行。
             * */
            boolean doTask(T data);
        }

    }
}
